﻿using System;
using System.Collections.Generic;
using System.Linq;
using BlobNet.Base.Collections;
using BlobNet.Base.Common;
using BlobNet.Base.Enums;
using BlobNet.Base.Interfaces;

namespace BlobNet.Base.Storage
{
    [Serializable]
    internal abstract class StorageBase
    {
        protected BlobDomain _blobDomain;
        protected Guid _entityId;

        protected StorageBase(Guid entityId, BlobDomain blobDomain)
        {
            if (entityId == Guid.Empty)
                throw new ArgumentException("Cannot be empty", "entityId");

            _entityId = entityId;
            _blobDomain = blobDomain;
        }

        #region enums

       
        protected internal Guid EntityId
        {
            get { return _entityId; }
        }

        protected internal BlobDomain BlobDomain
        {
            get { return _blobDomain; }
        }

        #region Nested type: StorageOperationType

        protected internal enum StorageOperationType
        {
            NotSet = 0,
            Add,
            Update
        }

        #endregion

        #region Nested type: SupportedObjectTypes

        protected internal enum SupportedObjectTypes
        {
            NotSupported = 0,
            List,
            Dictionary
        }

        #endregion

        #endregion enums

        public abstract void FillFrom(IStorageManager currentStorage);

        public abstract void ClearData();
       

        public abstract bool CanDettach();

        public abstract IList<IPersisteable> GetVariantSourcesItems();

        protected SupportedObjectTypes GetSupportedObjectType<TPropertyType>(TPropertyType value)
        {
            Type c, w;
            return GetSupportedObjectType(value, out c, out w);
        }

        protected SupportedObjectTypes GetSupportedObjectType<TPropertyType>(TPropertyType value, out Type currentType,
                                                                             out Type typeWrapper)
        {
            SupportedObjectTypes result = SupportedObjectTypes.NotSupported;
            currentType = value != null ? value.GetType() : typeof (TPropertyType);
            typeWrapper = null;

            if (
                (currentType.IsGenericType &&
                 TypesHelper.GetGenericType(currentType, typeof (IList<>)).IsAssignableFrom(currentType)))
            {
                Type[] genericArguments = currentType.GetGenericArguments();

                Type genericArgument = genericArguments[0];
                if (genericArgument.IsValueType ||
                    typeof (BlobPart).IsAssignableFrom(genericArgument))
                {
                    typeWrapper = typeof (BlobList<>);
                    result = SupportedObjectTypes.List;
                }
            }
            else if (
                (currentType.IsGenericType &&
                 TypesHelper.GetGenericType(currentType, typeof (IDictionary<,>)).IsAssignableFrom(currentType)))
            {
                //TODO:CASE DICTIONARY CALL WRAPPER, the key MUST BE string
            }

            return result;
        }

        public abstract object SetStatusValue<TPropertyType>(string propertyName, TPropertyType value);
       


        public abstract TPropertyType GetStatusValue<TPropertyType>(string propertyName);
       

        public abstract bool HasStatusValue(string propertyName);
        

       
    }
}